package br.mikhas.container.factory;

import br.mikhas.util.Assert;

/**
 * Abstract implementation of {@link BeanFactory} that has a parent factory and
 * looks for resources on it in case of a resource definition does not exists on
 * it.
 * 
 * @author Mikhail Domanoski
 */
public abstract class HierarchicalBeanFactory implements BeanFactory {

	/**
	 * The parent {@link BeanFactory}
	 */
	protected BeanFactory parent;

	/**
	 * Default constructor
	 */
	public HierarchicalBeanFactory() {

	}

	public HierarchicalBeanFactory(BeanFactory parent) {
		this.setParent(parent);
	}

	/**
	 * Gets the parent bean definition or <code>null</code> if none;
	 */
	public BeanFactory getParentBeanFactory() {
		return this.parent;
	}

	/**
	 * Checks if this Bean factory contains the resource without checking on the
	 * parent factories
	 * 
	 * @param name
	 *            The name of the resource to check
	 */
	abstract boolean containsResource(String name);

	/**
	 * Gets and resource from one of the registered scopes or creates it if the
	 * ResourceDefinition is registered.
	 * 
	 * @param name
	 *            The name of the resource
	 * @return The instance of the resource
	 */
	protected abstract Object doGetResource(String name);

	/**
	 * Gets the resource from this {@link BeanFactory}. If the resource is not
	 * found, it looks on the parent factory.
	 */
	public final Object getResource(String name) {
		if (this.containsResource(name)) {
			return this.doGetResource(name);
		} else {
			BeanFactory parent = this.getParentBeanFactory();

			if (parent != null) {
				return parent.getResource(name);
			}

		}

		return null;
	}

	/**
	 * Sets this factory parent
	 * 
	 * @param factory
	 *            The parent {@link BeanFactory}
	 */
	protected void setParent(BeanFactory factory) {
		Assert.notNull(factory, "Parent factory must not be null");
		this.parent = factory;
	}
}
